//
// afix_deque.c
//

#include "chlds_deque.h"
#include "chlds_memory.h"

#ifdef __cplusplus
extern "C" {
#endif

sint32 deque_create(TDeque* pDeque, const sint32 elen)
{
    pDeque->head = 15;
    pDeque->tail = 0;
    pDeque->used = 0;
    pDeque->elen = elen;
    pDeque->size = pDeque->head + 1;
    pDeque->data = MEMORY_ALLOC(pDeque->size * pDeque->elen);
    MEMORY_ZERO(pDeque->data, pDeque->size * pDeque->elen);

    return 0;
}

sint32 deque_release(TDeque* pDeque)
{
    MEMORY_FREE(pDeque->data);
    pDeque->data = NULL;
    pDeque->head = 0;
    pDeque->tail = 0;
    pDeque->used = 0;
    pDeque->elen = 0;
    pDeque->size = 0;

    return 0;
}

sint32 deque_extend(TDeque* pDeque)
{
    void* p = MEMORY_ALLOC(pDeque->size * pDeque->elen * 2);
    MEMORY_ZERO(p, pDeque->size * pDeque->elen * 2);

    MEMORY_COPY(p, pDeque->data, (pDeque->head + 1) * pDeque->elen);
    MEMORY_COPY(MEMORY_OFFSET(p, pDeque->tail + pDeque->size, pDeque->elen),
        MEMORY_OFFSET(pDeque->data, pDeque->tail, pDeque->elen),
        pDeque->elen *((pDeque->size - pDeque->tail) % pDeque->size));

    MEMORY_FREE(pDeque->data);
    pDeque->data = p;
    pDeque->tail += (pDeque->size * (pDeque->tail ? 1 : 0));
    pDeque->size *= 2;

    return 0;
}

sint32 deque_push_head(TDeque* pDeque, const void* p)
{
    pDeque->used++;
    if (pDeque->head < (pDeque->size - 1))
        pDeque->head++;
    else
        pDeque->head = 0;

    MEMORY_COPY(MEMORY_OFFSET(pDeque->data, pDeque->head, pDeque->elen), p, pDeque->elen);

    if (pDeque->used == pDeque->size)
    /*if (((pDeque->head + 1) % pDeque->size) == pDeque->tail)*/
        deque_extend(pDeque);

    return 0;
}

sint32 deque_push_tail(TDeque* pDeque, const void* p)
{
    pDeque->used++;
    if (pDeque->tail > 0)
        pDeque->tail--;
    else
        pDeque->tail = pDeque->size - 1;

    MEMORY_COPY(MEMORY_OFFSET(pDeque->data, pDeque->tail, pDeque->elen), p, pDeque->elen);

    if (pDeque->used == pDeque->size)
    /*if (((pDeque->head + 1) % pDeque->size) == pDeque->tail)*/
        deque_extend(pDeque);

    return 0;
}

void* deque_pop_head(TDeque* pDeque)
{
    void* p = MEMORY_OFFSET(pDeque->data, pDeque->head, pDeque->elen);

    if (pDeque->used < 1)
        return NULL;
    pDeque->used--;

    if (pDeque->head > 0)
        pDeque->head--;
    else
        pDeque->head = pDeque->size - 1;

    return p;
}

void* deque_pop_tail(TDeque* pDeque)
{
    void* p = MEMORY_OFFSET(pDeque->data, pDeque->tail, pDeque->elen);

    if (pDeque->used < 1)
        return NULL;
    pDeque->used--;

    if (pDeque->tail < (pDeque->size - 1))
        pDeque->tail++;
    else
        pDeque->tail = 0;

    return p;
}

sint32 deque_used(const TDeque* pDeque)
{
    return pDeque->used;
}

#ifdef __cplusplus
}
#endif

